package com.yunchao.library.lock

import java.nio.ByteBuffer
import java.nio.ByteOrder

/**
 * EPC区数据结构（严格遵循12字节规范）
 */
data class EPCInfo(
    val rawData: ByteArray
) {
    init {
        require(rawData.size == 12) { "EPC数据必须为12字节" }
    }

    // ========== 字段解析（严格按图片规范） ==========

    // 1. 签封ID (32bit = 4字节) - 序号1
    val sealId: Int
        get() = ByteBuffer.wrap(rawData, 0, 4)
            .order(ByteOrder.BIG_ENDIAN).int

    // 2. 版本号 (4bit) - 序号2（单独解析）
    val version: Int
        get() = (rawData[4].toInt() and 0xF0) shr 4

    // 3. 券别类型 (4bit) - 序号3（单独解析）
    val voucherType: VoucherType
        get() = VoucherType.fromBinary(
            (rawData[4].toInt() and 0x0F)
                .toString(2)
                .padStart(4, '0')
        )

    // 4. 张数 (16bit = 2字节) - 序号4
    val sheetCount: Int
        get() = ((rawData[5].toInt() and 0xFF) shl 8) or
                (rawData[6].toInt() and 0xFF)

    // 5. 随机数 (8bit = 1字节) - 序号5
    val randomNumber: Int
        get() = rawData[7].toInt() and 0xFF

    // 6. 操作计数器 (12bit) - 序号6
    val operationCounter: Int
        get() = ((rawData[8].toInt() and 0xFF) shl 4) or
                ((rawData[9].toInt() and 0xF0) shr 4)

    // 7. 校验码 (12bit) - 序号7
    val checksum: Int
        get() = ((rawData[9].toInt() and 0x0F) shl 8) or
                (rawData[10].toInt() and 0xFF)

    // 8. 状态字 (8bit = 1字节) - 序号8
    val status: LockStatus
        get() = LockStatus(rawData[11])

    // ========== 辅助方法 ==========
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false
        other as EPCInfo
        return rawData.contentEquals(other.rawData)
    }

    override fun hashCode(): Int = rawData.contentHashCode()
}


/**
 * 券别类型枚举（4bit）
 */
enum class VoucherType(
    val binaryCode: String,
    val amount: Double,
    val displayName: String,
    val voucherId: String
) {
    RMB_100("0001", 100.00, "纸币100元", "101001"),  // 二进制0001对应100元
    RMB_50("0010", 50.00, "纸币50元", "101002"),    // 二进制0010对应50元
    RMB_20("0011", 20.00, "纸币20元", "101003"),    // 二进制0011对应20元
    RMB_10("0100", 10.00, "纸币10元", "101004"),    // 二进制0100对应10元
    RMB_5("0101", 5.00, "纸币5元", "101005"),      // 二进制0101对应5元
    RMB_1("0110", 1.00, "纸币1元", "101007"),      // 二进制0110对应1元
    UNKNOWN("0000", 0.00, "非法卷别", "000000");    // 二进制0000保留

    companion object {
        // 金额到券别的映射
        private val amountMapping = VoucherType.entries.associateBy { it.amount }

        // 二进制码到券别的映射
        private val binaryMapping = VoucherType.entries.associateBy { it.binaryCode }

        fun fromAmount(amount: Double): VoucherType {
            return amountMapping[amount] ?: UNKNOWN
        }

        fun fromBinary(binary: String): VoucherType {
            require(binary.length == 4) { "券别编码必须为4位二进制" }
            return binaryMapping[binary] ?: UNKNOWN
        }
    }
}

/**
 * 状态字解析（严格遵循图片中的位定义）
 */
data class LockStatus(val statusByte: Byte) {

    //1Bit/0Bit：锁状态标志： 00：开；01：关；11：未知；10：非法
    val lockState: LockState
        get() = when ((statusByte.toInt() shr 1) and 0x02 or (statusByte.toInt() and 0x01)) {
            0b00 -> LockState.OPEN     // bit1=0, bit0=0
            0b01 -> LockState.CLOSED   // bit1=0, bit0=1
            0b10 -> LockState.INVALID  // bit1=1, bit0=0
            0b11 -> LockState.UNKNOWN  // bit1=1, bit0=1
            else -> throw IllegalStateException()
        }

    // 2bit: 异常标志：0为正常/1为异常；
    val isAbnormal: Boolean
        get() = (statusByte.toInt() and 0x04) != 0

    // 3bit: EPC异常标志：0为正常/1为异常
    val isEpcAbnormal: Boolean
        get() = (statusByte.toInt() and 0x08) != 0

    // 6bit: 上电标志：0为未上电/1为上电
    val isPoweredOn: Boolean
        get() = (statusByte.toInt() and 0x40) != 0

    // 7bit: 工作标志：0为工作完成/工作未开始，1为工作中
    val isWorking: Boolean
        get() = (statusByte.toInt() and 0x80) != 0
}

enum class LockState {
    OPEN,      // 00
    CLOSED,    // 01
    INVALID,   // 10
    UNKNOWN    // 11
}


fun main() {

    val epcStr = "49737753114E20BB00503141"

    val epcBytes = epcStr.chunked(2).map { it.toInt(16).toByte() }.toByteArray()

    val epcDomain = EPCInfo(epcBytes)

    println(epcDomain.sealId)
    println(epcDomain.version)
    println(epcDomain.voucherType.amount)
    println(epcDomain.sheetCount)
    println(epcDomain.randomNumber)
    println(epcDomain.operationCounter)
    println(epcDomain.checksum)
    println(epcDomain.status.lockState)
    println(epcDomain.status.isAbnormal)
    println(epcDomain.status.isEpcAbnormal)
    println(epcDomain.status.isPoweredOn)
    println(epcDomain.status.isWorking)


}